import tkinter as tk
from tkinter import filedialog
import constants as const
import os
from leftMenuGuide import LeftMenuGuide
from eventcenter import eventcenter as event
from datacenter import datacenter as dc
from tools import tools

class LeftPanel(tk.Frame):
    def __init__(self, root):
        super().__init__(root,)
        self.root = root
        self.grid(row=0, column=0, sticky="ns")
        
        self.selectlayer = const.UNSELECTED
        self.selectcard =  const.UNSELECTED

        self.layers = []

        self.init_event()
        
        # 绑定Ctrl+S快捷键到save_file方法
        self.root.bind("<Control-s>", lambda event: self.save_file())

        # 创建容器 Frame
        self.create_widgets()
    def initcanvas(self):
        # 创建 Canvas
        canvas = tk.Canvas(self, width=200)
        canvas.grid(row=1, column=0, sticky="ns")
        self.canvas = canvas

        # 创建滚动条
        scrollbar= tk.Scrollbar(self, orient="vertical", command=canvas.yview)
        scrollbar.grid(row=1, column=1, sticky="ns")

        # 配置 Canvas 滚动条
        canvas.config(yscrollcommand=scrollbar.set)
  
        # 创建 Frame
        self.frame = tk.Frame(canvas)
        self.window = self.canvas.create_window(0, 0, window=self.frame, anchor="nw")

        # 设置滚动区域
        self.canvas.bind("<Configure>", self._on_configure)

        # 配置右侧布局的行和列权重
        self.grid_rowconfigure(1, weight=1)
        self.grid_columnconfigure(0, weight=1)

        self.start_y = 0  # 记录点击时的位置

        self.refresh_guide_menu()


    def _on_configure(self, event=None):
        self.canvas.config(scrollregion=self.canvas.bbox("all"))

    def _on_mouse_click(self, event):
        self.start_y = event.y

    def _on_mouse_drag(self, event):
        dy = event.y - self.start_y
        self.canvas.yview_scroll(-1 * int(dy / 20), "units")  # 根据实际需求调整单位
        self.start_y = event.y

    def _on_mouse_wheel(self, event):
        if event.num == 4 or event.delta > 0:  # 向上滚动
            self.canvas.yview_scroll(-1, "units")
        elif event.num == 5 or event.delta < 0:  # 向下滚动
            self.canvas.yview_scroll(1, "units")

    def init_event(self):
        event.add_event(const.event_guide_menu_cliciked, self.event_on_menu_click)
        event.add_event(const.event_on_menu_refreh, self.event_on_menu_refreh)
        event.add_event(const.event_reset_all, self.event_reset_all)
        # event.add_event(const.event_card_value_changed, self.event_card_value_changed)

    def create_widgets(self):
        fm1 = tk.Frame(self)
        fm1.grid(row=0, column=0, sticky="ew")

        # 注册验证函数
        validate_cmd = self.register(self.validate_input)
        # 关卡编号输入框
        self.lv_entry = tk.Entry(fm1, validate="key",validatecommand=(validate_cmd, '%P'), width=8)
        self.lv_entry.pack(side=tk.LEFT)
        self.lv_entry.insert(0, "100000")  # 设置默认值
        # 绑定回车键事件
        self.lv_entry.bind("<Return>", lambda event: self.open_file())
        self.lv_entry.bind("<KP_Enter>", lambda event: self.open_file())

        # 新建一层按钮
        tk.Button(fm1, text="open",command=self.open_file).pack(side=tk.LEFT, padx=3)
        tk.Button(fm1, text="save",command=self.save_file).pack(side=tk.LEFT, padx=3)
        tk.Button(fm1, text="+",command=self.add_new_layer).pack(side=tk.LEFT, padx=3)
        tk.Button(fm1, text="-",command=self.del_layer).pack(side=tk.LEFT, padx=3)

        self.initcanvas()

    def validate_input(self, new_value):
        return len(new_value) == 0 or (new_value.isdigit() and len(new_value) <= 6)

    def set_cards(self, layerid, cardids = [], foreRefresh = False, index = const.NONE_INT):
        if layerid >=0 :
            self.layers[layerid].set_cards(cardids, index, foreRefresh)

    def add_new_layer(self):
        if not dc.curmap.isLoad():
            return tools.toast("请先打开地图")

        index = dc.curmap.new_layer()
        self.refresh_guide_menu(index)

    def del_layer(self):
        if not dc.curmap.isLoad():
            return tools.toast("请先打开地图")
            
        ls = dc.curmap.del_layer()
        if len(ls) > 0:
            self.refresh_guide_menu()
            event.dispatch_event(const.event_on_del_card, ls)

    def select_card(self, cardid, layerid, index):
        self.selectlayer = const.UNSELECTED
        self.selectcard = const.UNSELECTED

        for i, layer in enumerate(self.layers):
            if layer.layerid == layerid:
                self.selectlayer = i
                self.selectcard = cardid
            else:
                layer.select_card()

    def refresh_guide_menu(self, index = const.NONE_INT):
        count = 0
        cuids = dc.curmap.cuids
        for i, cards in enumerate(cuids):
            count += 1
            layer = self.layers[i] if i < len(self.layers) else None
            if not layer:
                layer = LeftMenuGuide(self.frame, i)
                layer.pack(fill=tk.X)
                self.layers.append(layer)
            else:
                if not layer.winfo_ismapped():
                    layer.pack(fill=tk.X)
                    
            
        if count < len(self.layers):
            for i in range(count, len(self.layers)):
                if self.layers[i].winfo_ismapped():
                    self.layers[i].clear()
                    self.layers[i].pack_forget()

        
        self.update_scrollregion()

    # 左侧导航菜单点击事件
    def event_on_menu_click(self, cardid, layerid, index):
        self.select_card(cardid, layerid, index)

    def update_scrollregion(self):
        # 动态计算 Frame 的大小
        self.canvas.update_idletasks()  # 确保所有布局更新完成
        new_width = self.frame.winfo_reqwidth()
        new_height = self.frame.winfo_reqheight()
        # 更新 Canvas 的窗口区域大小
        self.canvas.itemconfig(self.window, width=new_width, height=new_height)
        # 更新 Canvas 的滚动区域
        self.canvas.config(scrollregion=self.canvas.bbox("all"))

    def event_on_menu_refreh(self):
        self.update_scrollregion()

    def open_file(self):
        filename = self.lv_entry.get()
        if len(filename) != 6:
            # 获取maps文件夹的路径
            maps_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'res', 'maps')
            # 打开文件选择对话框，默认显示maps文件夹下的json文件
            file_path = filedialog.askopenfilename(
                initialdir=maps_dir,
                title="选择地图文件",
                filetypes=[("JSON文件", "*.json")]
            )
            if file_path:  # 确保用户选择了文件而不是取消
                file_name = os.path.splitext(os.path.basename(file_path))
                filename = file_name[0]
                self.lv_entry.insert(0, os.path.basename(filename))
            else:
                return tools.toast("取消加载")

        dc.load_mapdata(filename)
        event.dispatch_event(const.event_reset_all)
        tools.toast("打开成功")
        
    def save_file(self):
        if not dc.curmap.isLoad():
            return tools.toast("没有需要保存的信息")
        filename = self.lv_entry.get()

        if len(filename) != 6:
            # 获取maps文件夹的路径
            maps_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'res', 'maps')
            # 打开文件保存对话框，默认显示maps文件夹下的json文件
            file_path = filedialog.asksaveasfilename(
                initialdir=maps_dir,
                title="保存地图文件",
                filetypes=[("JSON文件", "*.json")],
                defaultextension=".json"
            )
            if file_path:  # 确保用户选择了文件而不是取消
                # 提取文件名（不含扩展名）
                file_name = os.path.splitext(os.path.basename(file_path))[0]
                filename = file_name
                # 更新输入框内容
                self.lv_entry.delete(0, tk.END)
                self.lv_entry.insert(0, filename)
            else:
                return tools.toast("取消保存")

        # 设置当前地图名称并保存
        tools.toast("保存成功" if dc.save_mapdata(filename) else "没有新的变更")

    def event_reset_all(self):
        for layer in self.layers:
            layer.refresh_layer()

        self.refresh_guide_menu()

    def event_card_value_changed(self, uid, refreshall = False):
        card = dc.get_card(uid)
        if card:
            self.select_card(card.cardid, card.layerid, card.index)
        